package cn.seaboot.admin.api.model;

import cn.seaboot.admin.api.bean.ApiModelField;
import cn.seaboot.admin.api.bean.ApiModelRule;
import cn.seaboot.commons.core.FastJsonUtils;
import cn.seaboot.commons.core.UUIDUtils;
import cn.seaboot.commons.exception.ReflectException;
import cn.seaboot.commons.reflect.ObjectField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Mr.css
 * @version 2024-07-19 15:40
 */
@Component
public class ValidatorScanner {
    private static final Logger logger = LoggerFactory.getLogger(ValidatorScanner.class);

    /**
     * 序列化 hibernate-validator 时，忽略这些参数字段
     */
    private static final String[] transientField = {"groups", "payload"};

    /**
     * 扫描字段所包含的 hibernate-validator
     *
     * @param field 字段对象
     */
    public List<ApiModelRule> scanFieldValidator(ApiModelField modelField, ObjectField field) {
        try {
            List<ApiModelRule> ret = new ArrayList<>();
            for (Annotation annotation : field.getAnnotations()) {
                Class<?> type = annotation.annotationType();
                String pkg = type.getName();
                //如果注解是 hibernate.validator 或者 javax.validation
                if (pkg.startsWith("org.hibernate.validator.constraints")
                        || pkg.startsWith("jakarta.validation.constraints")
                        || pkg.startsWith("javax.validation.constraints")) {

                    // 字段校验规则
                    String rule = this.serializeValidator(annotation, type);

                    // 获取 validator 分组
                    Method m = type.getMethod("groups");
                    Class<?>[] groups = (Class<?>[]) m.invoke(annotation);
                    for (Class<?> group : groups) {

                        // 持久化数据校验规则
                        ApiModelRule fr = new ApiModelRule();
//                        fr.setId(UUIDUtils.genUUID32());
//                        fr.setRule(rule);
//
//                        fr.setProjectId(modelField.getProjectId());
//                        fr.setFieldId(modelField.getId());
//                        fr.setGroup(group.getName());
//                        ret.add(fr);
                    }
                }
            }
            return ret;
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            throw new ReflectException("scan field rule failed", e);
        }
    }

    /**
     * 序列化参数校验
     *
     * @param annotation 注解
     * @return map
     */
    public String serializeValidator(Annotation annotation, Class<?> type) throws InvocationTargetException, IllegalAccessException {
        Method[] methods = type.getDeclaredMethods();
        Map<String, Object> map = new HashMap<>(methods.length);

        //将注解名称作为类型
        map.put("_type", type.getSimpleName());
        for (Method method : methods) {
            String methodName = method.getName();
            //忽略非必要的参数，减少数据量
            if (isTransientField(methodName)) {
                Object value = method.invoke(annotation);
                String str = value == null ? null : value.toString();
                map.put(method.getName(), str);
            }
        }
        return FastJsonUtils.toJSONString(map);
    }

    /**
     * 序列化的时候，忽略某些字段
     * <p>
     * Ignore some useless validator field
     *
     * @param fieldName -
     * @return boolean
     */
    private static boolean isTransientField(String fieldName) {
        for (String str : transientField) {
            if (str.equals(fieldName)) {
                return false;
            }
        }
        return true;
    }
}
